﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pifagor.IG;
using Pifagor.Exceptions;

namespace Pifagor.Runtime
{
	public class InternalFunction : IFunction
	{
		IGInternalFunctionType _functionType;

		public InternalFunction(IGConstant constant)
		{
			if (constant.Type != IGConstantType.InternalFunction)
				throw new ArgumentException("Internal function constant is not recognized. Constant type must be InternalFunction.");

			_functionType = constant.InternalFunctionType;
		}

		public Value Run(Value argumentValue)
		{
			switch (_functionType)
			{
				case IGInternalFunctionType.Mul:
					{
						if (argumentValue.Type != ValueType.DataList)
							throw new RuntimeException("Mul internal function argument must be datalist");

						if (argumentValue.DataListValue.Items.Length != 2)
							throw new RuntimeException("Mul internal function datalist argument must contain 2 elements");

						var computedItems = argumentValue.DataListValue.Items.Select(item => item.Compute()).ToArray();

						if (!computedItems.All(listItem => listItem.Type == ValueType.Integer))
							throw new RuntimeException("Mul internal function datalist argument must contain only integers");

						return new Value(computedItems[0].IntegerValue * computedItems[1].IntegerValue);
					}


				case IGInternalFunctionType.Add:
					{
						if (argumentValue.Type != ValueType.DataList)
							throw new RuntimeException("Add internal function argument must be datalist");

						if (argumentValue.DataListValue.Items.Length != 2)
							throw new RuntimeException("Add internal function datalist argument must contain 2 elements");

						var computedItems = argumentValue.DataListValue.Items.Select(item => item.Compute()).ToArray();
						if (!computedItems.All(listItem => listItem.Type == ValueType.Integer))
							throw new RuntimeException("Add internal function datalist argument must contain only integers");

						return new Value(computedItems[0].IntegerValue + computedItems[1].IntegerValue);
					}

				default:
					throw new RuntimeException("Function type not recognized");
			}
		}
	}
}
